package com.atguigu.gmall.cart.service.impl;

import java.math.BigDecimal;
import java.sql.Savepoint;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constans.RedisConstant;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.AuthUtil;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.feign.product.ProductFeign;
import com.atguigu.gmall.model.cart.CartItem;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.model.to.UserAuthTo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.api.R;
import com.fasterxml.jackson.core.type.TypeReference;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @author A
 * @version 1.0
 * @description: TODO
 * @date 2025/9/9 23:11
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    ProductFeign productFeign;
    @Qualifier("otherThreadPool")
    @Autowired
    ThreadPoolExecutor otherThreadPool;
    //添加购物车
    @Override
    public CartItem addCart(Long skuId, Integer skuNum) {
        //判断是否用临时用户id为键
        String userCartKey = determineUserCartKey();
        validateCartNum(userCartKey);
        //保存购物车
        CartItem cartItem = saveCart(skuId, skuNum, userCartKey);
        //设置临时购物车过期时间
        if (AuthUtil.getAuthTo().getUserId() ==null){
            setCartExpire(userCartKey);
        }


        return cartItem;
    }
    //判断购物车数量是否超过最大限制
    public void validateCartNum(String userCartKey) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(userCartKey);
        if (operations.size() >= RedisConstant.CART_MAX_SIZE) {
            throw new GmallException(ResultCodeEnum.CART_FULL_ERROR);
        }
    }

    //设置临时购物车过期时间
    private void setCartExpire(String userCartKey) {
        redisTemplate.expire(userCartKey, RedisConstant.CART_EXPIRE_TIME);
    }

    //保存购物车去reids中,数据结构为hash
    private CartItem saveCart(Long skuId, Integer skuNum, String userCartKey) {
        BoundHashOperations<String, String, String> boundedCart = redisTemplate.boundHashOps(userCartKey);
        CartItem cartItemFromDb = getCartItemFromDb(skuId, skuNum);
        //判断购物车中是否已经有该商品
        Boolean hasKey = boundedCart.hasKey(skuId.toString());
        if (!hasKey) {
            //第一次添加购物车直接保存
            boundedCart.put(skuId.toString(), JsonUtil.toStr(cartItemFromDb));
            return cartItemFromDb;
        } else {
            //非第一次添加购物车,更新数量
            String cartJson = boundedCart.get(skuId.toString());
            CartItem cartItemfromRedis = JsonUtil.jsonToObject(cartJson, new TypeReference<CartItem>() {
            });
            cartItemfromRedis.setSkuNum(cartItemfromRedis.getSkuNum() + skuNum);
            boundedCart.put(skuId.toString(), JsonUtil.toStr(cartItemfromRedis));
            return cartItemfromRedis;
        }

    }

    //从数据库中获取sku信息,包装返回cartItem
    @Override
    public CartItem getCartItemFromDb(Long skuId, Integer skuNu) {

        // 从数据库中查询sku信息
        SkuInfo skuInfo = productFeign.getSkuInfo(skuId);
        CartItem cartItem = new CartItem();
        cartItem.setIsCollect(0);
        cartItem.setId(skuInfo.getId());
        //有user_id使用userId,没有使用userTempId
        String determineUserId = determineUserId();
        cartItem.setUserId(determineUserId);
        cartItem.setSkuId(skuId);
        cartItem.setCartPrice(skuInfo.getPrice());
        cartItem.setSkuNum(skuNu);
        cartItem.setSkuDefaultImg(skuInfo.getSkuDefaultImg());
        cartItem.setSkuName(skuInfo.getSkuName());
        cartItem.setIsChecked(1);
        cartItem.setCreateTime(new Date());
        cartItem.setUpdateTime(new Date());
        cartItem.setSkuPrice(skuInfo.getPrice());
        return cartItem;
    }

    //获取购物车列表
    @Override
    public List<CartItem> getCartList() {
        //判断是否合并临时用户购物车
        //1.如果临时购物车有数据,用户购物车也有数据,合并
        BoundHashOperations<String, String, String> userCartBound = getUserCartBound();
        BoundHashOperations<String, String, String> userTempCartBound = getTempUserCartBound();
        if (userCartBound != null && userTempCartBound != null && userTempCartBound.size() > 0) {
            if (userCartBound.size()+userTempCartBound.size() > RedisConstant.CART_MAX_SIZE){
                throw new GmallException(ResultCodeEnum.CART_FULL_ERROR);
            }
            //需要合并临时购物车到用户购物车
            String tempCartKey = getTempCartKey();
            String userCartKey = getUserCartKey();
            List<CartItem> tempCartItems = getItems(tempCartKey);
            List<CartItem> cartItems = getItems(userCartKey);
            Map<Long, CartItem> cartItemMap =new HashMap<>();
            Stream.concat(cartItems.stream(), tempCartItems.stream())
                    .collect(Collectors.toList())
                    .forEach(
                            cartItem -> {
                               CartItem newCartItem = cartItem;
                                //判断是否已经存在,如果存在,数量相加,如果不存在,直接添加
                                if (cartItemMap.containsKey(cartItem.getSkuId())) {
                                    //判断是否添加收藏,如果添加收藏,则更新isCollect

                                    newCartItem= cartItemMap.get(cartItem.getSkuId());
                                    if (cartItem.getIsCollect() == 1){
                                        newCartItem.setIsCollect(1);
                                    }
                                    newCartItem.setSkuNum(cartItem.getSkuNum()+newCartItem.getSkuNum());
                                }
                                //键是唯一的,所以直接覆盖
                                cartItemMap.put(cartItem.getSkuId(), newCartItem);
                            }
                    );
            //删除临时购物车
            deleteByCartKey(tempCartKey);
            deleteByCartKey(userCartKey);
            //删除用户购物车
            List<CartItem> collect = cartItemMap.values().stream().collect(Collectors.toList());
            //新保存用户购物车,并更新实时价格
            collect.forEach(cartItem -> {
                userCartBound.put(cartItem.getSkuId().toString(), JsonUtil.toStr(cartItem));
            });
            //异步更新实时价格
            batchUpdateCartPrice(userCartKey);
            return collect;
        } else {
            //不需要合并临时购物车到用户购物车
            String cartKey = determineUserCartKey();
            BoundHashOperations<String, String, String> boundedCart = redisTemplate.boundHashOps(cartKey);
            List<CartItem> cartItemList = boundedCart.values().stream()
                    .map(cartItemStr -> {
                        return JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
                        });
                    })
                    .sorted((o2, o1) -> o1.getUpdateTime().compareTo(o2.getUpdateTime()))
                    .collect(Collectors.toList());
            //异步更新实时价格
            batchUpdateCartPrice(cartKey);
            return cartItemList;
        }
    }
    //批量更新实时价格
    public void batchUpdateCartPrice(String cartKey) {
        otherThreadPool.submit(()->{
            List<CartItem> cartItems = getItems(cartKey);
            if (cartItems == null || cartItems.size() <= 0) {
                throw new GmallException(ResultCodeEnum.USER_CART_ITEM_NOT_EXIST);
            }
           cartItems.stream().forEach(cartItem -> {
               BigDecimal skuInfoPrice = productFeign.getSkuInfoPrice(cartItem.getSkuId());
               cartItem.setSkuPrice(skuInfoPrice);
               redisTemplate.boundHashOps(cartKey).put(cartItem.getSkuId().toString(), JsonUtil.toStr(cartItem));
           });
        },otherThreadPool);
    }

    //删除这个key下的所有数据
    private void deleteByCartKey(String cartKey) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(cartKey);
        operations.values().stream().forEach(cartItemStr -> {
            CartItem cartItem = JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
            });
            String skuId = cartItem.getSkuId().toString();
            redisTemplate.boundHashOps(cartKey).delete(skuId);
        });
    }

    private List<CartItem> getItems(String cartKey) {
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(cartKey);
        List<String> values = operations.values();
        if (values == null || values.size() <= 0) {
            return null;
        }
        List<CartItem> collect = values.stream().map(cartItemStr -> {
            return JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
            });
        }).collect(Collectors.toList());
        return collect;
    }

    private String getTempCartKey() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserTempId() == null) {
            return null;
        }
        return RedisConstant.USER_CART_PREFIX + authTo.getUserTempId();
    }

    private String getUserCartKey() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserId() == null) {
            return null;
        }
        return RedisConstant.USER_CART_PREFIX + authTo.getUserId();
    }

    //更改购物车中商品的数量
    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        String cartKey = determineUserCartKey();
        CartItem cartItem = getCartItemBySkuId(skuId, cartKey);
        if (skuNum == 1 || skuNum == -1) {
            cartItem.setSkuNum(cartItem.getSkuNum() + skuNum);
            //写回redis
        } else {
            cartItem.setSkuNum(skuNum);
        }
        cartItem.setUpdateTime(new Date());
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        operations.put(skuId.toString(), JsonUtil.toStr(cartItem));
    }

    @Override
    public void checkCart(Long skuId, Integer check) {
        String cartKey = determineUserCartKey();
        CartItem cartItem = getCartItemBySkuId(skuId, cartKey);
        cartItem.setIsChecked(check);
        redisTemplate.boundHashOps(cartKey).put(skuId.toString(), JsonUtil.toStr(cartItem));
    }

    @Override
    public void deleteCart(Long skuId) {
        String cartKey = determineUserCartKey();
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(cartKey);
        operations.delete(skuId.toString());
    }

    //删除选中的
    @Override
    public void deleteChecked() {
        String cartKey = determineUserCartKey();
        BoundHashOperations<String, String, String> cartBound = redisTemplate.boundHashOps(cartKey);
        //获取选中的id字符串数组
        Object[] ids = cartBound.values().stream()
                .map(cartItemStr -> {
                    return JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
                    });
                })
                .filter(cartItem -> cartItem.getIsChecked() == 1)
                .map(cartItem -> cartItem.getSkuId().toString())
                .toArray();
        if (ids.length <= 0) {
            throw new GmallException(ResultCodeEnum.USER_CART_ITEM_NOT_EXIST);
        }
        //删除选中的id
        cartBound.delete(ids);
    }

    //全选或全不选
    @Override
    public void checkCartAllTo(Integer isChecked) {
        String cartKey = determineUserCartKey();
        BoundHashOperations<String, String, String> bounded = redisTemplate.boundHashOps(cartKey);
        List<String> values = bounded.values();
        if (values == null || values.size() <= 0) {
            throw new GmallException(ResultCodeEnum.USER_CART_ITEM_NOT_EXIST);
        }
        values.stream()
                .map(cartItemStr -> {
                    return JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
                    });
                }).forEach(cartItem -> {
                    if (cartItem == null) {
                        throw new GmallException(ResultCodeEnum.USER_CART_ITEM_NOT_EXIST);
                    }
                    cartItem.setIsChecked(isChecked);
                    bounded.put(cartItem.getSkuId().toString(), JsonUtil.toStr(cartItem));
                });
    }

    @Override
    public void addCollect(Long skuId) {
        String cartKey = determineUserCartKey();
        String userId = determineUserId();
        CartItem cartItem = getCartItemBySkuId(skuId, cartKey);
        cartItem.setIsCollect(1);
        //保存到collect中
        BoundHashOperations<String, String, String> collectBound = redisTemplate.boundHashOps(RedisConstant.USER_COLLECT_PREFIX + userId);
        collectBound.put(skuId.toString(), JsonUtil.toStr(cartItem));
        //保存到cart中
        BoundHashOperations<String, String, String> cartBound = redisTemplate.boundHashOps(cartKey);
        cartBound.put(skuId.toString(), JsonUtil.toStr(cartItem));
    }

    //取消收藏
    @Override
    public void cancelCollect(Long skuId) {
        //1.从redis中删除收藏
        String userId = determineUserId();
        BoundHashOperations<String, String, String> collectBound = redisTemplate.boundHashOps(RedisConstant.USER_COLLECT_PREFIX + userId);
        collectBound.delete(skuId.toString());
        //2.从cart中更改isCollect=0
        String cartKey = determineUserCartKey();
        CartItem cartItem = getCartItemBySkuId(skuId, cartKey);
        cartItem.setIsCollect(0);
        BoundHashOperations<String, String, String> cartBound = redisTemplate.boundHashOps(cartKey);
        cartBound.put(skuId.toString(), JsonUtil.toStr(cartItem));
    }

    //获取收藏列表
    @Override
    public List<CartItem> getCollectList() {
        String userId = determineUserId();
        BoundHashOperations<String, String, String> collectBound = redisTemplate.boundHashOps(RedisConstant.USER_COLLECT_PREFIX + userId);
        List<String> values = collectBound.values();
        if (values == null || values.size() <= 0) {
            return null;
        }
        List<CartItem> collects = values.stream().map(cartItemStr -> {
                    return JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
                    });
                }).filter(cartItem -> cartItem.getIsCollect() == 1)
                .collect(Collectors.toList());
        return collects;
    }

    //移除收藏
    @Override
    public void removeCollect(Long skuId) {
        //1.从redis中删除收藏
        String userId = determineUserId();
        BoundHashOperations<String, String, String> collectBound = redisTemplate.boundHashOps(RedisConstant.USER_COLLECT_PREFIX + userId);
        collectBound.delete(skuId.toString());
        //2.从cart中更改isCollect=0
        String cartKey = determineUserCartKey();
        CartItem cartItem = getCartItemBySkuId(skuId, cartKey);
        cartItem.setIsCollect(0);
        BoundHashOperations<String, String, String> cartBound = redisTemplate.boundHashOps(cartKey);
        cartBound.put(skuId.toString(), JsonUtil.toStr(cartItem));
    }

    @Override
    public List<CartItem> getCheckedCartItems() {
        Long userId = AuthUtil.getAuthTo().getUserId();
        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(RedisConstant.USER_CART_PREFIX + userId);
        List<CartItem> cartItemList = ops.values().stream()
                .map(cartItemJson -> {
                    return JsonUtil.jsonToObject(cartItemJson, new TypeReference<CartItem>() {
                    });
                }).filter(cartItem -> {
                    return cartItem.getIsChecked() == 1;
                }).collect(Collectors.toList());

        return cartItemList;
    }

    private CartItem getCartItemBySkuId(Long skuId, String cartKey) {
        BoundHashOperations<String, String, String> cartBound = redisTemplate.boundHashOps(cartKey);
        String cartItemStr = cartBound.get(skuId.toString());
        if (StringUtils.isBlank(cartItemStr)) {
            throw new GmallException(ResultCodeEnum.USER_CART_ITEM_NOT_EXIST);
        }
        CartItem cartItem = JsonUtil.jsonToObject(cartItemStr, new TypeReference<CartItem>() {
        });
        return cartItem;
    }

    //决定用户购物车的key
    private String determineUserCartKey() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserId() != null) {
            return RedisConstant.USER_CART_PREFIX + authTo.getUserId();
        } else {
            //临时用户id一定不为null
            return RedisConstant.USER_CART_PREFIX + authTo.getUserTempId();
        }
    }

    //决定用户的id
    private String determineUserId() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserId() != null) {
            return authTo.getUserId().toString();
        } else {
            //临时用户id一定不为null
            return authTo.getUserTempId();
        }
    }

    private BoundHashOperations<String, String, String> getUserCartBound() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserId() == null) {
            return null;
        }
        return redisTemplate.boundHashOps(RedisConstant.USER_CART_PREFIX + authTo.getUserId());
    }

    private BoundHashOperations<String, String, String> getTempUserCartBound() {
        UserAuthTo authTo = AuthUtil.getAuthTo();
        if (authTo.getUserTempId() == null) {
            return null;
        }
        return redisTemplate.boundHashOps(RedisConstant.USER_CART_PREFIX + authTo.getUserTempId());
    }
}
